package fr.labri.macchiato.ui.cart;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.ui.TextBox;
import com.smartgwt.client.types.Visibility;
import com.smartgwt.client.widgets.IconButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.VisibilityChangedEvent;
import com.smartgwt.client.widgets.events.VisibilityChangedHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;

import fr.labri.macchiato.core.model.Item;
import fr.labri.macchiato.core.model.Article;
import fr.labri.macchiato.core.model.Offer;
import fr.labri.macchiato.core.model.Product;
import fr.labri.macchiato.core.service.ProjectService;
import fr.labri.macchiato.core.service.Services;
import fr.labri.macchiato.core.technical.MObservable;
import fr.labri.macchiato.core.technical.MObserver;
import fr.labri.macchiato.ui.cart.events.ValidateSearchHandler;

/**
 * <p>
 * The widget which represent a row in the cart <br>
 * May represent an {@link Item}, a {@link Article} or an {@link Offer}
 * </p>
 * 
 * @author Paul SARRAUTE
 * 
 */
public class CartRow extends VLayout implements MObserver {

	private final static String ARTICLE_STYLE_NAME = "cartArticleLine";
	private final static String MODEL_STYLE_NAME = "cartModelLine";
	private final static String OFFER_STYLE_NAME = "cartOfferLine";

	private Product entry;
	private final String productName;
	private final HLayout headerLayout;
	private IconButton expandButton, removeButton;
	private Label nameLabel, priceLabel;
	private TextBox quantityField;
	private ProductSearch productSearch;

	/**
	 * Create a row which represent a specific product
	 * 
	 * @param productEntry
	 *            A product from the cart
	 */
	CartRow(Product productEntry, final String cartName,
			final String projectName) {
		entry = productEntry;
		entry.addObserver(this);

		String expandButtonToolTip = null;
		String productPrice = null;

		if (productEntry instanceof Item) {
			setStyleName(ARTICLE_STYLE_NAME);
			productSearch = new ModelSearch(productEntry.getName());
			expandButtonToolTip = "Chercher les modèles correspondants";
			productPrice = "";
		} else if (productEntry instanceof Article) {
			setStyleName(MODEL_STYLE_NAME);
			Article model = (Article) productEntry;
			productSearch = new OfferSearch(model.getEan());
			expandButtonToolTip = "Chercher les offres correspondantes";
			productPrice = "";
		} else if (productEntry instanceof Offer) {
			setStyleName(OFFER_STYLE_NAME);
			Offer offer = (Offer) productEntry;
			productSearch = new OfferSearch(offer.getEan());
			expandButtonToolTip = "Chercher les offres équivalentes";
			productPrice = NumberFormat.getCurrencyFormat().format(
					offer.getPrice() * productEntry.getQuantity());
		}

		productName = productEntry.getName();
		setWidth100();
		setHeight("3em");
		setMembersMargin(15);

		headerLayout = new HLayout(15);
		addMember(headerLayout);

		expandButton = new IconButton("");
		expandButton.setLargeIcon("/icons/search.png");
		expandButton.setOrientation("vertical");
		expandButton.setTooltip(expandButtonToolTip);
		headerLayout.addMember(expandButton);

		nameLabel = new Label(productName);
		nameLabel.setWidth("*");
		nameLabel.setStyleName("productLabel");
		headerLayout.addMember(nameLabel);

		quantityField = new TextBox();
		quantityField.setWidth("20");
		quantityField.setText(String.valueOf(productEntry.getQuantity()));
		quantityField.addKeyPressHandler(new KeyPressHandler() {
			public void onKeyPress(KeyPressEvent event) {
				if (!Character.isDigit(event.getCharCode()))
					((TextBox) event.getSource()).cancelKey();
			}
		});
		quantityField.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				getProjectService().setQuantity(projectName, cartName, entry,
						Integer.valueOf(quantityField.getText()));
			}

		});
		headerLayout.addMember(quantityField);

		priceLabel = new Label(productPrice);
		priceLabel.setWidth(125);
		priceLabel.setStyleName("productLabel");
		headerLayout.addMember(priceLabel);

		removeButton = new IconButton("");
		removeButton.setIcon("/icons/delete.png");
		removeButton.setOrientation("vertical");
		headerLayout.addMember(removeButton);

		expandButton.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				displaySearch();
			}

		});

	}

	private void displaySearch() {
		productSearch.startSearch();
		addMember(productSearch);
		productSearch
				.addVisibilityChangedHandler(new VisibilityChangedHandler() {

					public void onVisibilityChanged(VisibilityChangedEvent event) {
						if (productSearch.getVisibility() == Visibility.HIDDEN) {
							expandButton.enable();
						}
					}
				});
		expandButton.disable();
	}

	/**
	 * Add a {@link ClickHandler} on the remove button
	 * 
	 * @param handler
	 *            The handler to be added
	 */
	public void addRemoveProductHandler(ClickHandler handler) {
		removeButton.addClickHandler(handler);
	}

	/**
	 * Add a {@link ValidateSearchHandler} on the validate button
	 * 
	 * @param handler
	 *            The handler to be added
	 */
	void addValidateHandler(ValidateSearchHandler handler) {
		productSearch.addValidateHandler(handler);
	}

	private void updatePrice() {
		if (entry instanceof Offer) {
			Offer offer = (Offer) entry;
			priceLabel.setContents(NumberFormat.getCurrencyFormat().format(
					offer.getPrice() * entry.getQuantity()));
		}
	}

	public void update(MObservable o, Object arg) {
		nameLabel.setContents(entry.getName());
		quantityField.setText(String.valueOf(entry.getQuantity()));
		updatePrice();
	}

	private ProjectService getProjectService() {
		return Services.getInstance().getProjectService();
	}

}
